package com.mlk.rbac.Service.impl;

import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.ListMultimap;
import com.google.common.collect.Lists;
import com.mlk.core.config.DeptConfig;
import com.mlk.core.exception.ParamException;
import com.mlk.core.util.JSONUtils;
import com.mlk.core.util.ServerResponse;
import com.mlk.core.util.SessionUtils;
import com.mlk.rbac.Service.SysDeptService;
import com.mlk.rbac.constant.RBACConstant;
import com.mlk.rbac.dto.DeptTreeDTO;
import com.mlk.rbac.mapper.SysDeptMapper;
import com.mlk.rbac.mapper.SysUserMapper;
import com.mlk.rbac.param.DeptParam;
import com.mlk.rbac.po.SysDept;
import com.mlk.rbac.po.SysUser;
import com.mlk.rbac.utils.LevelUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.annotation.Resource;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.List;

/**
 * 组织部门服务
 *
 * @author xulu
 */
@Service
public class SysDeptServiceImpl implements SysDeptService {

    @Resource
    private SysDeptMapper sysDeptMapper;

    @Resource
    private SysUserMapper sysUserMapper;

    @Autowired
    private RedisTemplate<String,String> redisTemplate;


    // 默认第一层的节点的父id都是为0的,这样方便以后查询等操作
    public static Integer DEFAULT_ROOT_PARENT_ID = 0;

    @Override
    @Transactional
    public ServerResponse save(DeptParam dept) {

        if (dept == null) {
            throw new ParamException("没有传递部门参数!");
        }
        // 没有传递父id,则默认为顶层组织
        if (dept.getParentId() == null) {
            dept.setParentId(DEFAULT_ROOT_PARENT_ID);
        }

        // 进行校验,同一层级下面不能有相同名称的部门
        if (!checkDeptName(dept.getParentId(), dept.getName())) {
            return ServerResponse.fail("在同层级下不能存在相同名称的部门");
        }

        SysDept sysDept = new SysDept();
        BeanUtils.copyProperties(dept, sysDept);

        // 计算level
        SysDept parentDept = sysDeptMapper.selectById(sysDept.getParentId());
        if (parentDept != null) {
            sysDept.setLevel(LevelUtils.calLevel(parentDept.getLevel(), String.valueOf(parentDept.getId())));
        } else {
            sysDept.setLevel(LevelUtils.ROOT_LEVEL);
        }

        sysDept.setOperator(SessionUtils.getSysUser().getName());
        sysDept.setOperateTime(new Date());

        int count = this.sysDeptMapper.insert(sysDept);
        if (count == 0) {
            return ServerResponse.fail("新增部门错误!");
        }
        // 将新数据刷入缓存之中
        this.redisTemplate.opsForValue().set(DeptConfig.CACHE_PREFIX+sysDept.getId(), JSONUtils.toJSONString(sysDept));

        return ServerResponse.ok("新增部门成功!");
    }

    /**
     * 校验同一层级下是否存在相同名称的部门
     *
     * @param parentId
     * @param name
     * @return
     */
    private boolean checkDeptName(Integer parentId, String name) {
        return this.sysDeptMapper
                .selectCount(new EntityWrapper<SysDept>(SysDept.builder().parentId(parentId).name(name).status(RBACConstant.DeptStatus.ok).build()))
                == 0;
    }

    /**
     * 将部门的信息转换为树形结构
     *
     * @return
     */
    public ServerResponse listTree() {

        // 获取所有的节点
        List<SysDept> deptList = sysDeptMapper.selectList(new EntityWrapper<SysDept>(SysDept.builder().status(RBACConstant.DeptStatus.ok).build()));
        // 获取适配对象
        List<DeptTreeDTO> dtoList = Lists.newArrayList();
        deptList.forEach((e) -> {
            dtoList.add(DeptTreeDTO.adapt(e));
        });

        // 转换为multiMap结构,其中键就是父id,后面就靠这个父id进行递归处理
        ListMultimap<Integer, DeptTreeDTO> multimap = ArrayListMultimap.create();
        dtoList.forEach((e) -> {
            multimap.put(e.getParentId(), e);
        });

        // 将相同父id的list进行排序操作
        for (Integer e : multimap.keySet()) {
            Collections.sort(multimap.get(e), Comparator.comparingInt(SysDept::getSeq));
        }

        // 选出根节点
        List<DeptTreeDTO> rootDto = multimap.get(DEFAULT_ROOT_PARENT_ID);

        return ServerResponse.ok(doTree(multimap, rootDto));
    }

    /***
     * 递归生成树形结构
     *
     * @return
     */
    private List<DeptTreeDTO> doTree(ListMultimap<Integer, DeptTreeDTO> sourceMapList, List<DeptTreeDTO> treeList) {

        treeList.forEach(e -> {
            e.setChildren(sourceMapList.get(e.getId()));
            doTree(sourceMapList, e.getChildren());
        });

        return treeList;
    }

    /**
     * 删除组织部门信息
     */
    @Override
    public ServerResponse deleteDept(Integer id) {
        if (id == null) {
            return ServerResponse.fail("删除的部门id不能为空");
        }

        // 先判断是否存在下级的部门
        if (checkExistsSubDept(id)) {
            return ServerResponse.fail("删除的部门存在子部门");
        }

        // 然后判断还部门下是否还有员工
        if(checkExistsEmp(id)){
            return ServerResponse.fail("该部门下还存在员工");
        }

        // 此时可以正常的删除掉部门(状态值改成droped)
        SysDept dept = SysDept
                .builder()
                .id(id)
                .status(RBACConstant.DeptStatus.droped)
                .operateTime(new Date())
                .operator(SessionUtils.getSysUser().getName())
                .build();
        int count = this.sysDeptMapper.updateById(dept);
        if (count == 0) {
            return ServerResponse.fail("删除部门失败!");
        }

        // 删除缓存之中的内容
        this.redisTemplate.delete(DeptConfig.CACHE_PREFIX+id);

        return ServerResponse.ok("删除部门成功!");
    }

    /**
     * 判断一个部门下是否存在员工
     * 如果存在员工,不允许删除
     * @param id
     * @return
     */
    private boolean checkExistsEmp(Integer id) {
       return  this.sysUserMapper.selectCount(new EntityWrapper<SysUser>(SysUser.builder().deptId(id).build())) != 0;
    }

    /**
     * 判断部门下是否存在子部门
     *
     * @param id
     * @return
     */
    private boolean checkExistsSubDept(Integer id) {
        // 看看父id相同的部门的数量是否为0
        return this.sysDeptMapper
                .selectCount(new EntityWrapper<SysDept>(SysDept.builder().parentId(id).status(RBACConstant.DeptStatus.ok).build())) != 0;
    }

    /**
     * 更新部门信息
     */
    @Override
    public ServerResponse updateDept(Integer id, String name, String remark, Integer seq) {
        if (id == null) {
            return ServerResponse.fail("更新的部门的id不能为空");
        }

        if (StringUtils.isBlank(name)) {
            return ServerResponse.fail("部门的名称不能为空");
        }

        SysDept dept = this.sysDeptMapper.selectById(id);

        if (StringUtils.equals(name, dept.getName())) {
            return ServerResponse.fail("修改前后的名称一致");
        }

        //判断是否在同一层级下有相同的部门
        if (!checkExistsSubDept(dept.getParentId())) {
            return ServerResponse.fail("在同一层级下存在相同的部门名称");
        }

        // 更新部门的信息
        dept = SysDept.builder()
                .id(id)
                .name(name)
                .remark(remark)
                .seq(seq)
                .operateTime(new Date())
                .operator(SessionUtils.getSysUser().getName())
                .build();

        int count = this.sysDeptMapper.updateById(dept);
        if (count == 0) {
            return ServerResponse.fail("更新部门失败");
        }

        // 刷新缓存的内容
        SysDept newDept = this.sysDeptMapper.selectById(id);
        this.redisTemplate.opsForValue().set(DeptConfig.CACHE_PREFIX+id,JSONUtils.toJSONString(newDept));

        return ServerResponse.ok("更新部门成功");
    }

    @Override
    public ServerResponse deptList() {
        List<SysDept> deptList = sysDeptMapper.selectList(new EntityWrapper<SysDept>(SysDept.builder().status(RBACConstant.DeptStatus.ok).build()));
        return ServerResponse.ok(deptList);
    }
}
